﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;

namespace SynoManager
{
    /// <summary>
    /// This class can automatically enumerate the attributes for a certain type.
    /// </summary>
    /// <typeparam name="TType">The type that this class manages. It will automatically search for classes that inherit from this type in all loaded assemblies.</typeparam>
    /// <typeparam name="TAttribute">The type of attribute to search for with each type.</typeparam>
    public class TypeAttributeManager<TType, TAttribute> : Dictionary<TAttribute, Type>
        where TAttribute : Attribute
    {
        /// <summary>
        /// Create a new TypeAttributeManager, and automatically populate it.
        /// </summary>
        public TypeAttributeManager()
        {
            Rebuild();
        }

        Type[] typeList;
        TAttribute[] attributeList;

        /// <summary>
        /// Rebuild the TypeAttributeManager, clearing it and rescanning all loaded assemblies.
        /// </summary>
        public void Rebuild()
        {
            Debug.WriteLine(String.Format("Rebuilding {0} with {1}", typeof(TType), typeof(TAttribute)), "TypeAttrbuteManager");
            base.Clear();
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    foreach (Type type in assembly.GetTypes())
                    {
                        if (typeof(TType).IsAssignableFrom(type))
                        {
                            TAttribute[] atts = (TAttribute[])type.GetCustomAttributes(typeof(TAttribute), true);
                            foreach (TAttribute att in atts)
                                this.Add(att, type);
                        }
                    }
                }
                catch (ReflectionTypeLoadException ex)
                {
                    Debug.WriteLine("ReflectionTypeLoadException: " + ex.Message);
                }
            }
            Debug.WriteLine(String.Format("Found {2} types of {0} with {1}", typeof(TType), typeof(TAttribute), this.Count), "TypeAttributeManager");

            typeList = new Type[base.Count];
            attributeList = new TAttribute[base.Count];

            int index = 0;
            foreach (TAttribute attribute in base.Keys)
            {
                attributeList[index] = attribute;
                typeList[index] = base[attribute];
                index++;
            }

            AfterRebuild();
        }

        protected virtual void AfterRebuild()
        {
            
        }

        /// <summary>
        /// Retrieve the attribute for a certain type
        /// </summary>
        /// <param name="type">The type to search for</param>
        /// <returns>The attribute associated with this instance</returns>
        public TAttribute this[Type type]
        {
            get
            {
                foreach (TAttribute att in base.Keys)
                {
                    if (base[att] == type)
                        return att;
                }
                return null;
            }
        }

        /// <summary>
        /// Get a list of all available types
        /// </summary>
        public Type[] Types
        {
            get { return typeList; }
        }

        /// <summary>
        /// Get a list of all available attributes
        /// </summary>
        public TAttribute[] Attributes
        {
            get { return attributeList; }
        }
    }
}
